package com.nuance.assignment.fileInfo.server.advice;

import org.apache.log4j.Logger;
import org.hibernate.validator.method.MethodConstraintViolation;
import org.hibernate.validator.method.MethodConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.nuance.assignment.fileInfo.shared.ResponseDTO;

/**
 * This controller advice translates all exceptions from controllers and returns
 * the standard response with exception messages This is the single point of
 * exception handling and reporting
 * 
 * @author parag
 *
 */
@ControllerAdvice
@SuppressWarnings("deprecation")
public class ExceptionHandlingControllerAdvice {
	private static final Logger logger = Logger
			.getLogger(ExceptionHandlingControllerAdvice.class);

	@Autowired
	private MessageSource messageSource;

	/**
	 * A separate exception handler for MethodConstraintViolationException as
	 * single exception can hold multiple messages
	 * 
	 * @param exception
	 * @return
	 */
	@ResponseBody
	@ExceptionHandler(MethodConstraintViolationException.class)
	public ResponseDTO<Void> handleException(
			MethodConstraintViolationException exception) {
		logger.error("There has been an exception while handling user request",
				exception);
		ResponseDTO<Void> response = new ResponseDTO<>();
		response.setSuccess(false);
		for (MethodConstraintViolation<?> methodConstraintViolation : exception
				.getConstraintViolations()) {
			String code = methodConstraintViolation.getMessage();
			if (StringUtils.hasText(code)) {
				try {
					response.getMessages().add(
							messageSource.getMessage(code, null,
									LocaleContextHolder.getLocale()));
				} catch (NoSuchMessageException noSuchMessageException) {
					response.getMessages().add(
							messageSource.getMessage("error.system", null,
									LocaleContextHolder.getLocale()));
				}
			} else {
				response.getMessages().add(
						messageSource.getMessage("error.system", null,
								LocaleContextHolder.getLocale()));
			}

		}
		return response;
	}

	/**
	 * Generic exception handler for all exceptions Exception's message is
	 * treated as a key to find corresponding error code in MessageSource If no
	 * such key is found, a generic system wide error message is populated in
	 * response and returned.
	 * 
	 * @param exception
	 * @return
	 */
	@ResponseBody
	@ExceptionHandler(Exception.class)
	public ResponseDTO<Void> handleException(Exception exception) {
		logger.error("There has been an exception while handling user request",
				exception);
		ResponseDTO<Void> response = new ResponseDTO<>();
		response.setSuccess(false);
		try {
			response.getMessages().add(
					messageSource.getMessage(exception.getMessage(), null,
							LocaleContextHolder.getLocale()));
		} catch (NoSuchMessageException noSuchMessageException) {
			response.getMessages().add(
					messageSource.getMessage("error.system", null,
							LocaleContextHolder.getLocale()));
		}
		return response;
	}

}
